package com.lin.filegraph.utils.model;

import com.lin.filegraph.utils.compdg.ComponentGraph;
import com.lin.filegraph.utils.compdg.ComponentNode;
import com.lin.filegraph.utils.model.ComponentInfo;
import com.lin.filegraph.utils.parser.node.JProjectNode;

import java.util.ArrayList;
import java.util.List;

/**
 * @description:
 * @author: linhuaixu
 * @time: 2023/5/18 11:00
 */
public class ProjectInfo {
    private JProjectNode root = null;

    private int LOC = 0;// ��Ŀ������
    private int validLOC = 0;
    private List<ComponentInfo> listOfCompInfo;// �����Ϣ�б�
    private int circleNumInFDG = 0;

    public ProjectInfo(JProjectNode root) {
        // TODO Auto-generated constructor stub
        this.root = root;
        listOfCompInfo = new ArrayList<>();
    }

    public void calculateProjectInfo() {
        ComponentGraph compDG = root.getCompDG();
        List<ComponentNode> listOfComponents = compDG.getAllComponents();
        for (ComponentNode component : listOfComponents) {
            ComponentInfo compInfo = new ComponentInfo(component, root);
            compInfo.calculateCompInfo();
            circleNumInFDG += compInfo.getCircleNumInSubFDG();
            listOfCompInfo.add(compInfo);
        }
        for (ComponentInfo compInfo : listOfCompInfo) {
            LOC += compInfo.getLOC();
            validLOC = compInfo.getValidLOC();
        }
        setCompsCallDepth(compDG);
    }

    public void displayProjectInfo() {
        System.out.println("display project basic info ...");
        System.out.println(root);
        System.out.println("LOC:" + LOC);
        System.out.println("num of components: " + listOfCompInfo.size());
        System.out.println("list of components: ");
        for (ComponentInfo compInfo : listOfCompInfo) {
            System.out.println(compInfo.getComponent());
        }
    }

    public ComponentInfo getComponentInfoByName(String strComponentName) {
        for (ComponentInfo comBasicInfo : listOfCompInfo) {
            if (comBasicInfo.getComponent().getStrComponentName().equals(strComponentName)) {
                return comBasicInfo;
            }
        }
        return null;
    }

    public ComponentInfo getComponentInfo(ComponentNode component) {
        for (ComponentInfo comBasicInfo : listOfCompInfo) {
            if (comBasicInfo.getComponent().equals(component)) {
                return comBasicInfo;
            }
        }
        return null;
    }

    public JProjectNode getRoot() {
        return root;
    }

    public int getLOC() {
        return LOC;
    }

    public int getValidLOC() {
        return validLOC;
    }

    public List<ComponentInfo> getListOfCompInfo() {
        return listOfCompInfo;
    }

    public void setCompsCallDepth(ComponentGraph compDG) {
        List<ComponentNode> startComps = new ArrayList<>();
        for (ComponentInfo cInfo : getListOfCompInfo()) {
            ComponentNode comp = cInfo.getComponent();
            if (compDG.getPreComponents(comp).isEmpty()) {
                startComps.add(comp);
                cInfo.setCallDepth(0);
            }
        }

        for (ComponentNode startComp : startComps) {
            List<ComponentNode> visitedComps = new ArrayList<>();
            DFS(compDG, startComp, visitedComps, 0);
        }
    }

    private void DFS(ComponentGraph compDG, ComponentNode node, List<ComponentNode> visitedNodes, int depth) {
        ComponentInfo cInfo = getComponentInfo(node);
        visitedNodes.add(node);
        depth++;
        if (cInfo.getCallDepth() < depth) {
            cInfo.setCallDepth(depth);
        } else {
            depth = cInfo.getCallDepth();
        }
        for (ComponentNode postNode : compDG.getPostComponents(node)) {
            if (!visitedNodes.contains(postNode)) {
                DFS(compDG, postNode, visitedNodes, depth);
            }
        }
    }

}
